<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<title>pup_event_ipc</title>
<meta content="Barry Kauler" name="author">
<meta content="IPC mechanism for Puppy Linux" name="description">
</head>
<body>
<table align="center" border="0" cellpadding="2" cellspacing="2" width="600">
  <tbody>
    <tr>
      <td valign="top">
<h1>Puppy's InterProcess Communication</h1>
<font color="#990000">Page updated June 29, 2013</font>&nbsp; <br>
<b>pup_event</b> is the generic name that I have given to the underlying
 ...how to describe it... code that does everything "under the bonnet", 
in the background, that makes your pup run nice. <br>
<br>
This page describes an implementation of <b>InterProcess Communication</b>
 in Puppy, that falls under the pup_event umbrella. So, this can be 
known as the "pup_event IPC" technique, to give it a name when 
referenced or discussed elsewhere.<br>
<br>
The method chosen is server-less, that is, works peer-to-peer. 
Applications send and receive messages between themselves directly, 
without an intermediate server or daemon. However, some applications can
 provide information that other applications request, and I use the word
 <b>server</b> in reference to them. I also refer to applications as <b>clients</b> of the IPC mechanism.<br>
<br>
Puppy's IPC mechanism offers various services to client applications:<br>
<ol>
  <li>IPC by synchronous message swapping.</li>
  <li>IPC by mailbox (asynchronous) message passing.</li>
  <li>Block hotplug events from the kernel.</li>
  <li>...more coming...<br>
  </li>
</ol>
There is a CLI 
(commandline) utility supporting IPC in Puppy, named 'pup_event_ipc', that can be used in 
shell scripts. Documentation is provided below to show how binary (compiled) 
applications can use IPC by means of library calls.<br>
<br>
<hr size="2" width="100%">
<h2>pup_event_ipc</h2>


        This is a CLI (commandline) application named 'pup_event_ipc'. It is 
designed to be used in shell scripts, acting as an intermediary to the pup_event IPC mechanism, 
enabling scripts to pass messages between each other. It is located at /sbin/pup_event_ipc.<br>
<br>
Usage of pup_event_ipc is shown by examples in the rest of this 
document. You can also run it like this to see some usage information:<br>
<pre># pup_event_ipc --help</pre>
The source code is at /usr/local/pup_event/pup_event_ipc.bac in the 
latest Puppy, also reproduced below. It is also available online in the 
Woof Fossil VCS repository (also this document) after anonymous login, 
at: <a href="http://bkhome.org/fossil/woof2.cgi/index">http://bkhome.org/fossil/woof2.cgi/index</a> <br>
<br>
The code can be examined to see how any other application can access the IPC mechanism.<br>
<br>
The commandline format of pup_event_ipc is this:<br>
<pre># pup_event_ipc "request:client[:message]" [-t &lt;n&gt;]</pre>
<blockquote><b>-t</b> &lt;n&gt;: Specifies timeout in milliseconds. Timeout will return with value=1.<br>
  <b>request</b>: Name of another application to send the message to<b>*</b>. Or,<br>
  <b>request</b>: Keyword to request information from the server. <br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; 
&nbsp; Supported keywords:&nbsp;&nbsp; block mailbox waitmail<br>
  <b>client</b>:&nbsp; Any single-word to identify client (usually sender) application<b>*</b>.<br>
  <b>message</b>: Any text string (that other side understands), up to 4000 bytes.<br>
</blockquote>
<b><big>*</big></b>The names for clients need to be unique. Choose 
anything you want, perhaps prefixing all names with your initials, for 
example John Smith could prefix with "js_".<br>
<br>
<hr size="2" width="100%">
<h2>Message formats</h2>
This section describes message formats. This is already introduced above, as:<br>
<pre>"request:client[:message]"</pre>
The various permutations of this are described below.<br>
        <h3>Synchronous message-swapping</h3>
Demonstrating synchronous message-swap between two different applications.<br>
In one terminal window I type this:<br>
        <pre># pup_event_ipc "js_app1:js_app2:some stuff from app2"</pre>
In another terminal window I type this:<br>
        <pre># pup_event_ipc "js_app2:js_app1:data from app1"</pre>
After launching both of them:<br>
First window:<br>
        <pre># pup_event_ipc "js_app1:js_app2:some stuff from app2"<br>data from app1</pre>
Second window:<br>
        <pre># pup_event_ipc "js_app2:js_app1:data from app1"<br>some stuff from app2</pre>
This is a very simple mechanism that can be use by two applications to 
perform a synchronization, or to pass messages between each other.<br>
        <br>
It is a simple swap, and both sides must post to the other. If only one 
side posts, the message will remain in the "mailbox" until the other side 
posts.<br>
The utility 'pup_event_ipc' blocks, that is, waits, until the swap is completed, before exiting.<br>
        <br>
Note, the CLI utility 'pup_event_ipc' does have a timeout option (-t n),
 so either side can terminate before the swap has completed.<br>
<h3>Mailbox (asynchronous) message passing</h3>
When a client posts a message to another client, it goes first into the 
IPC "mailbox", later it gets delivered to the other client.<br>
<br>
With asynchronous message passing, you don't send the message to the 
other client, you send it to the mailbox only, then the sending-client 
is free to do other stuff.<br>
The other client, to which you would like your message to go, can at any
 time query "is there a message waiting for me?" and if so, 
fetch it.<br>
<br>
The format of messages is:<br>
<pre>"mailbox:client[:message]"</pre>
If a client posts a message with this format, with the third-field 
message-string, it gets posted, and the server acknowledges. For 
example:<br>
<pre># pup_event_ipc "mailbox:js_app1:message string posted to app1"<br>Mailbox acknowledge</pre>
A client, any client, can ask if there is mail waiting for "js_app1". 
This is done by having no third field. For example:<br>
<pre># pup_event_ipc "mailbox:js_app1"<br>message string posted to app1</pre>
However, if this is done again:<br>
<pre># pup_event_ipc "mailbox:js_app1"<br>Mailbox empty</pre>
That last example returns immediately, but if you want to wait until a message arrives at the mailbox, use this variant:<br>
<pre># pup_event_ipc "waitmail:js_app1"</pre>
The utility will not exit until there is a message delivered.<br>
<br>
But of course, the pup_event_ipc utility does support a timeout:<br>
<pre># pup_event_ipc "waitmail:js_app1:" -t 4000</pre>

Synchronous message-swapping and asynchronous mailbox message-passing, 
are the two peer-to-peer messaging and synchronization mechanisms.<br>
There is another group, that is a bit more like a server-client 
arrangement, in which the 'request' field of the message requests 
something from another application. That other application will be 
serving a certain kind of information. Although I don't really want to 
consider these as servers, as they are just equal clients in the IPC 
mailbox system, for the sake of putting a name on them, I am referring 
to this group of applications as "server applications".<br>
<br>
Server applications are documented below. Currently only <b>block</b> server is offered.<br>
<h3>Block hotplug events</h3>
A client application may query the "kernel-event server application" for
 various information, such as detecting plugin/removal of USB or 
card drives.<br>
<br>
For now, only <b>block</b> is supported. For example:<br>
<pre># pup_event_ipc "block:js_app1"<br>add:sdc add:sdc1</pre>
The utility waits until a drive hotplug event occurs, such as a USB Flash stick plugged in, then returns with the information.<br>
<br>
The 'pup-event_ipc' utility is only designed as a one-shot query, so exits after detecting the events.<br>
However, hotplug events are not lost. The first "block" request has 
registered "js_app1" (from above example) and hotplug events will 
accumulate.<br>
<br>
So, by having a loop, to receive and process the hotplug events, no events will be missed. Ex shell script:<br>
<pre>while true; do<br>&nbsp;EVENTS="`pup_event_ipc "block:js_app1"`"<br>&nbsp;...<i>process</i>...<br>done</pre>
What needs to be understood about the above, is how simple the 
implementation is. The client application just creates a file (if it 
does not exist) named "/tmp/pup_event_ipc/block_js_app1" and waits for 
the server-application to put something into it. This inotify IPC 
technique is described in the next section.<br>
<br>
<hr size="2" width="100%">
<h2>The inotify backend</h2>
The IPC technique used is more than a little unusual. The established 
techniques such as D-Bus, named pipes, message queues and Unix Domain 
Sockets, were investigated and rejected for one reason or another.<br>
<br>
The inotify mechanism supported by the Linux kernel is not intended to 
be used for IPC, at least not to the extent that I have done. As it has 
turned out, however, it "ticks all the boxes" for what I want for Puppy 
-- it is very fast, low resources, extremely simple, and remarkably 
amenable to the particular uses that I wanted to put it to.<br>
<br>
The References Section below has links that introduce inotify, read those if you need to understand the fundamentals. <br>
<br>
There is a directory /tmp/pup_event_ipc, the "mailbox", that 
contains the files that have the messages to be transferred. When a file
 pertaining to a particular client changes, the client "wakes up" and 
handles it. Basically the steps are:<br>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
  <tbody>
    <tr>
      <td valign="top"><b>1</b><br>
      </td>
      <td valign="top"><b>2</b><br>
      </td>
      <td valign="top"><b>3</b><br>
      </td>
    </tr>
    <tr>
      <td valign="top">ClientA is waiting on fileA<br>
      </td>
      <td valign="top">ClientB writes to fileA</td>
      <td valign="top">ClientA wakes up and reads file<br>
      </td>
    </tr>
  </tbody>
</table>
<br>
That is really all it is. From those three steps, a complete IPC system can be devised.<br>
<br>
Of course, there all kinds of caveats and gotchas in this mechanism, 
such as guaranteeing a complete message is written to a file before it 
is read, and that files do not contain garbled messages if two or more 
clients write to them simultaneously.<br>
<br>
The way that I have implemented it, does, I think, avoid these pitfalls.<br>
Atomicity of read and write is important for this to work, and from 
reading online I got two different figures for this for Linux: 1KB or 
4KB (kilobytes). I was optimistic and used the higher figure.<br>
<br>
A communication is between two clients, using two files, for each 
direction of transfer. As long as they choose unique names, there is not
 going to be a clash with other transfers. There will not occur the 
problem of two different clients simultaneously writing to the same 
file.<br>
<br>
Anyway, even if two or more clients were allowed to write to the same 
file "simultaneously", atomicity and the O_APPEND write mode (see 
below), will ensure that individual messages remain intact.<br>
<br>
The CLI utility is the first implementation of inotify-based IPC for 
Puppy Linux, though, it is generic and will work for all Linux 
distributions. The easiest way I think to explain how it all "hangs 
together" is to show the code for this utility.<br>
<br>
The utility 'pup_event_ipc' is written in BaCon (see: <a href="http://bkhome.org/bacon/">http://bkhome.org/bacon</a>) with embedded C, so is a binary executable, small and fast. This is the code as at June 29, 2013:<br>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
  <tbody>
    <tr>
      <td valign="top">
        <pre>REM (c) Copyright Barry Kauler, June 2013, bkhome.org<br>REM License GPL3 (refer: /usr/share/doc/legal)<br>REM InterProcess Communication for Puppy Linux, CLI utility using inotify.<br>REM 130628 first version.<br><br>DECLARE helpflg,milliseconds TYPE int<br><br>'parse the commandline...<br>helpflg=0<br>milliseconds=0<br>sendstr$=""<br>IF argc==1 THEN helpflg=1<br>FOR x=1 TO argc-1<br> arg$=argv[x]<br> IF arg$=="--help" THEN<br>  helpflg=1<br>  CONTINUE<br> ENDIF<br> IF arg$=="-h" THEN<br>  helpflg=1<br>  CONTINUE<br> ENDIF<br> IF arg$=="-t" THEN<br>  INCR x<br>  milliseconds=VAL(argv[x])<br>  CONTINUE<br> END IF<br> sendstr$=arg$<br>NEXT<br><br>IF helpflg==1 THEN<br> PRINT "(c) Copyright Barry Kauler, June 2013, license GPL3 (/usr/share/doc/legal)"<br> PRINT "This is a CLI utility that may be used in scripts. Run like this:"<br> PRINT " pup_event_ipc \"request:client[:message]\""<br> PRINT " request: name of another application to send the message to*. Or,"<br> PRINT " request: keyword to request information. Supported keywords:"<br> PRINT "          block mailbox waitmail"<br> PRINT " client:  any single-word to identify client (usually sender) application*."<br> PRINT " message: any text string (that other side understands), up to 4000 bytes."<br> PRINT "          any characters allowed, including \":\""<br> PRINT "ex: pup_event_ipc \"otherapp:myapp:some data for otherapp\""<br> PRINT "ex: pup_event_ipc \"mailbox:otherapp:some data for otherapp\""<br> PRINT "ex: pup_event_ipc \"mailbox:myapp\"" <br> PRINT "ex: pup_event_ipc \"waitmail:myapp\""<br> PRINT "ex: pup_event_ipc \"block:myapp\""<br> PRINT "pup_event_ipc has an optional timeout (milliseconds),"<br> PRINT "ex: pup_event_ipc -t 1000 \"otherapp:myapp:data for you\""<br> PRINT "Will exit with non-zero value if an error:"<br> PRINT " 1=timeout. 2=wrong msg format. 3-7=message-passing failure. "<br> PRINT "*Any unique names that both clients agree on."<br> PRINT "PLEASE SEE /usr/local/pup_event/pup_event_ipc-README.htm for more details."<br> END 0<br>END IF<br><br>PROTO close, ftruncate, inotify_init, inotify_add_watch, inotify_rm_watch<br>PROTO lseek, open, poll, read, sizeof, strlen, write<br>DECLARE fd1,len1,leni,size_buf,thiswatchfile,otherwatchfile TYPE int<br>DECLARE arr1,thisapp,otherapp TYPE char*<br>DECLARE thisdescr,otherdescr TYPE int<br>size_char=sizeof(char)<br>size_inbuf=size_char*4096<br>DECLARE inbuf,bufinotify TYPE char ARRAY size_inbuf<br><br>SUB exitsub(NUMBER i)<br> IF watchdir&gt;0 THEN <b>inotify_rm_watch</b>(fd1,watchdir)<br> IF fd1&gt;0 THEN <b>close</b>(fd1)<br> IF otherdescr&gt;0 THEN <b>close</b>(otherdescr)<br> IF thisdescr&gt;0 THEN <b>close</b>(thisdescr)<br> END i<br>END SUB<br><br>'struct pollfd, defined in asm-generic/poll.h...<br>RECORD pfd<br> LOCAL fd TYPE int<br> LOCAL events TYPE short<br> LOCAL revents TYPE short<br>END RECORD<br>'linux/poll.h, only includes asm/poll.h, which only includes asm-generic/poll.h...<br>CONST POLLIN=1<br>pfd.events = POLLIN<br><br>SUB waitsub()<br> 'there is very slight possibility of deadlocking, if reply between lseek &amp; read/poll...<br> offt=<b>lseek</b>(thisdescr,0,SEEK_END)<br> IF offt==0 THEN<br>  IF milliseconds==0 THEN<br>   'this will block until the file is modified...<br>   leni=<b>read</b>(fd1,bufinotify,size_inbuf)<br>  ELSE<br>   pfd.fd=fd1<br>   eventstatus=<b>poll</b>(&amp;pfd.fd,1,milliseconds)<br>   IF eventstatus==0 THEN exitsub(1)<br>   IF eventstatus&lt;0 THEN exitsub(7)<br>  ENDIF<br> ENDIF<br> offt=<b>lseek</b>(thisdescr,0,SEEK_SET)<br> numr=<b>read</b>(thisdescr,inbuf,size_inbuf)<br> ft=<b>ftruncate</b>(thisdescr,0)<br> IF numr&gt;1 THEN<br>  'get rid of carriage-return char...<br>  inbuf[numr-1]=0<br>  inbuf$=inbuf<br>  PRINT inbuf$<br> ENDIF<br>END SUB<br><br>'parse the message...<br>field1$=""<br>field2$=""<br>field3$=""<br>field4$=""<br>message$=""<br>arr1=sendstr$<br>off1=INSTR(arr1,":")<br>IF off1=0 THEN exitsub(2)<br>arr1[off1-1]=0<br>field1$=arr1<br>off2=INSTR(arr1+off1,":")<br>arr1[off1+off2-1]=0<br>field2$=arr1+off1<br>IF off2&gt;0 THEN<br> off3=INSTR(arr1+off1+off2,":")<br> 'the message-part can have ":" chars in it...<br> message$=arr1+off1+off2<br> arr1[off1+off2+off3-1]=0<br> field3$=arr1+off1+off2<br> IF off3&gt;0 THEN<br>  off4=INSTR(arr1+off1+off2+off3,":")<br>  arr1[off1+off2+off3+off4-1]=0<br>  field4$=arr1+off1+off2+off3<br> ENDIF<br>ENDIF<br>'need to extract names of this-app and other-app...<br>otherapp=0<br>thisapp=0<br>thiscreateflag=1<br>SELECT field1$<br>CASE "mailbox"<br> IF message$!="" THEN<br>  otherapp=field2$<br> ELSE<br>  thisapp=field2$<br> ENDIF<br>CASE "waitmail"<br> thisapp=field2$<br>CASE "block"<br> thisapp$=CONCAT$("block_",field2$)<br> thisapp=thisapp$<br> 'thisfile$ is not created here, it is created by daemon that monitors kernel uevents...<br> thiscreateflag=0<br>DEFAULT<br> otherapp=field1$<br> thisapp=field2$<br>END SELECT<br><br>'create the files...<br>otherdescr=0<br>thisdescr=0<br>watchdir=0<br>IF FILEEXISTS("/tmp/pup_event_ipc")==0 THEN MAKEDIR "/tmp/pup_event_ipc"<br>IF otherapp!=0 THEN<br> otherfile$=CONCAT$("/tmp/pup_event_ipc/",otherapp)<br> USEC<br>  /*defined in /usr/include/asm-generic/fcntl.h &amp; i386-linux-gnu/bits/fcntl-linux.h...*/<br>  #define O_WRONLY	00000001<br>  #define O_CREAT	00000100<br>  # define O_SYNC	04010000<br>  #define O_FSYNC	O_SYNC<br>  #define O_APPEND	00002000<br>  otherdescr=<b>open</b>(otherfile$, O_WRONLY | O_CREAT | O_APPEND);<br> END USEC<br> IF otherdescr&lt;=0 THEN exitsub(3)<br>ENDIF<br>IF thisapp!=0 THEN<br> closedflag=0<br> thisfile$=CONCAT$("/tmp/pup_event_ipc/",thisapp)<br> IF thiscreateflag=1 THEN<br>  USEC<br>   #define O_RDONLY	00000000<br>   #define O_CREAT	00000100<br>   #define O_RDWR	00000002<br>   thisdescr=<b>open</b>(thisfile$,O_RDWR | O_CREAT);<br>  END USEC<br> ELSE<br>  IF FILEEXISTS(thisfile$)==1 THEN<br>   USEC<br>    #define O_RDONLY	00000000<br>    #define O_RDWR	00000002<br>    thisdescr=<b>open</b>(thisfile$,O_RDWR);<br>   END USEC<br>  ELSE<br>   closedflag=1<br>  ENDIF<br> ENDIF<br> IF closedflag==0 THEN<br>  IF thisdescr&lt;=0 THEN exitsub(4)<br>  fd1=<b>inotify_init</b>()<br>  IF fd1&lt;=0 THEN exitsub(5)<br>  CONST IN_MODIFY=2<br>  watchdir=<b>inotify_add_watch</b>(fd1,thisfile$,IN_MODIFY)<br>  IF watchdir&lt;=0 THEN exitsub(6)<br> ENDIF<br>ENDIF<br><br>'now decide what to do...<br>SELECT field1$<br>CASE "mailbox"<br> IF otherapp!=0 THEN<br>  'need to post message to otherapp... format: "mailbox:otherapp:message"<br>  outstr$=CONCAT$(message$,"\n")<br>  wr=<b>write</b>(otherdescr,outstr$,strlen(outstr$))<br>  PRINT "Mailbox acknowledge"<br> ELSE<br>  'need to check if waiting mail for thisapp...<br>  offt=<b>lseek</b>(thisdescr,0,SEEK_END)<br>  IF offt==0 THEN<br>   PRINT "Mailbox empty"<br>  ELSE<br>   offt=<b>lseek</b>(thisdescr,0,SEEK_SET)<br>   numr=<b>read</b>(thisdescr,inbuf,size_inbuf)<br>   ft=<b>ftruncate</b>(thisdescr,0)<br>   IF numr&gt;1 THEN<br>    'get rid of carriage-return char...<br>    inbuf[numr-1]=0<br>    inbuf$=inbuf<br>    PRINT inbuf$<br>   ENDIF<br>  ENDIF<br> ENDIF<br>CASE "waitmail"<br> 'need to wait for mail for thisapp... format: "waitmail:thisapp"<br> waitsub()<br>CASE "block"<br> 'need to wait for block-drive hotplug event, for thisapp... format: "block:thisapp"<br> IF FILEEXISTS(thisfile$)==0 THEN<br>  PRINT "Not implemented"<br> ELSE<br>  waitsub()<br> ENDIF<br>DEFAULT<br> 'post msg to otherapp, wait for reply to thisapp... format: "otherapp:thisapp:message"<br> outstr$=CONCAT$(message$,"\n")<br> wr=<b>write</b>(otherdescr,outstr$,strlen(outstr$))<br> waitsub()<br>END SELECT<br><br>exitsub(0)<br></pre>
      </td>
    </tr>
  </tbody>
</table>
<br>
This is a remarkably small program to implement a complete IPC system. Essentially, it does this:<br>
<ol>
  <li>Parses the message that has been passed on the commandline.</li>
  <li>Creates one or two files in /tmp/pup_event_ipc, and opens them.</li>
  <li>Based on the passed message, data will be written to one file, or data read from the other.</li>
  <li>Reading may or may not block, depending on the message.<br>
  </li>
</ol>
When a file is opened for writing, it is done with the 'O_APPEND' mode, 
meaning that writes to it always append to the end of the file, totally 
ignoring the file-pointer.<br>
Messages are line-based, that is, one message per line. This allows 
messages to accumulate, while waiting to be read -- hence, most 
important, no messages get lost.<br>
<br>
Take the message "block:myapp" as an example. The name "myapp" is an 
arbitrary choice, anything unique is suitable. If this is posted by the 
CLI utility:<br>
<pre># pup_event_ipc "block:myapp"</pre>
If you were to trace through the above code, you would see that if file 
"/tmp/pup_event_ipc/block_myapp" is opened (or created if it does not 
exist), then there is a block on waiting for something to be written to 
the file.<br>
When something is written to the file, it is read, and the file zeroised. The read contents are printed on stdout.<br>
<br>
The above scenario means that some other application must write to /tmp/pup_event_ipc/block_myapp. <br>
In the very latest builds of Puppy, we do have a an application that 
detects drive hotplug activity, a daemon named <b>pup_event_frontend_d</b>, that performs this information server function.<br>
<br>
The function that such a server would have to perform can be show by a shell script:<br>
<pre>for ONEFILE in `ls /tmp/pup_event_ipc/block_*`<br>do<br>&nbsp;echo $BLOCKINFO &gt;&gt; $ONEFILE<br>done</pre>
That's it, done. All clients that are waiting on block-drive hotplug 
notification, will "wake up" and read the data. As mentioned before, it 
does not matter if a client is in a loop, doing other stuff:<br>
<pre>while true; do<br>&nbsp;EVENTS="`pup_event_ipc "block:myapp"`"<br>&nbsp;...<i>other stuff</i>...<br>done</pre>
While executing "other stuff", any new block-drive events will append to
 /tmp/pup_event_ipc/block_myapp (that is, queue )until it is next read.<br>
<br>
Note: For the above example, the code in pup_event_ipc does not 
automatically create /tmp/pup_event_ipc/block_myapp. This is for usage 
in older puppies and other distros. In latest experimental Puppy builds 
however, the line "thiscreateflag=0" is commented out, we have the 
pup_event_frontend_d daemon that feeds kernel block-drive events (as 
described above).<br>
pup_event_frontend_d is described further in the next section.<br>
<br>
There is a lot that can be said about the flexibility of this 
inotify-based IPC mechanism. Just one example: although the 
pup_event_ipc utility does have a timeout option, you can cause a 
timeout whenever you want -- say, for example that a shell script has 
executed "pup_event_ipc 'block:myapp'" and is blocked, waiting on a 
modification to file /tmp/pup_event_ipc/block_myapp. Well, if you just 
execute "touch /tmp/pup_event_ipc/block_myapp", the read() function that
 is waiting will return, with zero data of course -- but voila, a simple
 way to cause a timeout.<br>
<br>
<hr size="2" width="100%"><h2>
Example code blocks</h2>
I will add to this section. For now, I have included code to show how 
the "server" can be implemented to serve block-drive event 
notifications.<br>
<br>
<h3>Block-drive event notification</h3>
It has been explained above, that a client application may request 
block-drive event notification by posting a message of format 
"block:myapp" to the IPC mailbox. <br>
<br>
Puppy Linux has a daemon, named <b>pup_event_frontend_d</b>, at 
/usr/local/pup_event (as well as the BaCon source file, 
pup_event_frontend_d.bac, and there is a wrapper script at /sbin). This 
daemon is started from /root/.xinitrc when X starts up. It does a lot of
 background stuff, such as manage the desktop drive icons. For that 
latter reason, it does have information about drive hotplug events.<br>
<br>
It was an easy matter to add a bit of extra code to pup_even_frontend_d,
 to post this information to clients that want it, via the IPC 
mechanism. Example shell script code is shown in the above section, how 
this can be done.<br>
<br>
The actual code inserted into pup_event_frontend_d is shown below. 
Basically, it looks for any files named /tmp/pup_event_ipc/block_*, then
 writes the drive hotplug information to them (string devevents$):<br>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
  <tbody>
    <tr>
      <td valign="top">
        <pre>PROTO opendir, readdir<br>DECLARE dir1 TYPE DIR*<br>DECLARE ent1 TYPE struct dirent*<br><br>dir1=<b>opendir</b>("/tmp/pup_event_ipc")<br>IF dir1!=NULL THEN<br> WHILE TRUE DO<br>  ent1=<b>readdir</b>(dir1)<br>  IF ent1==NULL THEN BREAK<br>  off1=<b>INSTR</b>((*ent1).d_name,"block_")<br>  IF off1!=0 THEN<br>   clientfile$=<b>CONCAT$</b>("/tmp/pup_event_ipc/",(*ent1).d_name)<br>   outmsg$=<b>CONCAT$</b>(devevents$,"\n")<br>   USEC<br>    #define O_WRONLY	00000001<br>    #define O_APPEND	00002000<br>    int clientdescr;<br>    clientdescr=<b>open</b>(clientfile$, O_WRONLY | O_APPEND);<br>    if (clientdescr&gt;0) {<br>     int wr=<b>write</b>(clientdescr,outmsg$,strlen(outmsg$));<br>     close(clientdescr);<br>    }<br>   END USEC<br>  ENDIF<br> WEND<br><br>ENDIF<br></pre>
      </td>
    </tr>
  </tbody>
</table>
<br>
Note, BaCon is just a translator to C, which is then compiled using the 
Gnu C compiler. It is really just a thin translation layer, so many 
C-isms can be put into the BaCon code, and pure C can be embedded. I use
 BaCon as I prefer the syntax, plus it has many higher-level features, 
such as better string handling, and associative arrays. It is easy to read the above and translate to all-C if required.<br>
<br>
...<i>more coming</i>...<br>
<br>
<br>
<hr size="2" width="100%"><h2>Feedback welcome</h2>
I will be posting about progress on pup_event to my blog, <a href="http://bkhome.org/blog2/">http://bkhome.org/blog2/</a>&nbsp; <br>
<br>
Feedback will be welcome. If you can think of anything that might 
compromise the integrity of data transfer with this technique, or code 
modifications that will add improvements (while still keeping everything
 simple, including simple and small code).<br>
<br>
Regards,<br>
Barry Kauler<br>
<br>
<hr size="2" width="100%"><h2>References</h2>
Reference on libc functions:<br>
<a href="http://www.gnu.org/software/libc/manual/html_node/Function-Index.html">http://www.gnu.org/software/libc/manual/html_node/Function-Index.html</a> <br>
Wikipedia:<br>
<a href="http://en.wikipedia.org/wiki/Inotify">http://en.wikipedia.org/wiki/Inotify</a>&nbsp; <br>
Intro to inotify:<br>
<a href="http://www.linuxjournal.com/article/8478">http://www.linuxjournal.com/article/8478</a>&nbsp; <br>
Monitor file system activity with inotify:<br>
<a href="http://www.ibm.com/developerworks/library/l-ubuntu-inotify/">http://www.ibm.com/developerworks/library/l-ubuntu-inotify/</a>&nbsp; <br>
Monitor Linux File System Events with Inotify:<br>
<a href="http://www.developertutorials.com/tutorials/linux/monitor-linux-inotify-050531-1133/">http://www.developertutorials.com/tutorials/linux/monitor-linux-inotify-050531-1133/</a>&nbsp; <br>
The inotify API:<br>
<a href="http://linux.die.net/man/7/inotify">http://linux.die.net/man/7/inotify</a>&nbsp; <br>
<br>
<br>
      </td>
    </tr>
    <tr>
      <td valign="top"><small>(c) Copyright Barry Kauler, 2013. All reproduction rights of this page are reserved.</small> <br>
      </td>
    </tr>
  </tbody>
</table>
<br>
<br>


</body></html>